package progetto1.csm.implementation;

import java.util.HashMap;
import java.util.Map;

import progetto1.csm.core.StatisticType;
import progetto1.csm.core.Statistics;
import progetto1.csm.core.SystemElement;
import progetto1.csm.core.actor.Client;
import progetto1.csm.core.actor.Watcher;
import sde.actor.Message;

public class CSMWatcher extends Watcher {
	
	private static class Init extends Message{}
	
	private final byte CREATED = 0, OPERATING = 1;
	private final int ARRAY_DIM = CSMSystemElements.values().length;
	private int[] pc = new int[ARRAY_DIM];//processed client dall'elemnto i
	private double [] deltaTime = new double[ARRAY_DIM];//sommatoria dei delta t dei processi che entrano nel sistema i
	private Map<Couple<SystemElement,Client>,Double> tarrives = new HashMap<Couple<SystemElement,Client>,Double>();//tempo di arrivo elemento di sistema / cliente
	private double [] eActivity = new double[ARRAY_DIM];//sommatoria delle deltat di attivita' dell'elemeto i del sistema
	private double [] eActivation = new double[ARRAY_DIM];//istante di attivazione dell'elemento i del sistema
	private CSMStatistics res = new CSMStatistics();
	
	protected CSMWatcher() {
	}
	
	protected void init(){
		send(new Init());
		become(CREATED);
	}

	@Override
	public void handler(Message m) {
		switch (currentStatus()) {
		case CREATED:
			if (m instanceof Init) {
				tarrives.clear();
				res.clear();
				for (int i = 0; i < deltaTime.length; i++) {
					pc[i] = 0;
					deltaTime[i] = 0;
					eActivity[i] = 0;
					eActivation[i] = -1;					
				}
				become(OPERATING);
			}
			break;
		case OPERATING:
			if (m instanceof Enter) {
				Enter e = (Enter) m;
				int index = e.getSystemElement().getOrdinal();
				if (eActivation[index] == -1) {// se l'elemento era in idle
					eActivation[index] = now();
				}
				tarrives.put(
						new Couple<SystemElement, Client>(e.getSystemElement(),
								e.getClient()), new Double(now()));
			} else if (m instanceof Exit) {
				Exit e = (Exit) m;
				int index = e.getSystemElement().getOrdinal();
				pc[index]++;
				double before = tarrives.remove(
						new Couple<SystemElement, Client>(e.getSystemElement(),
								e.getClient())).doubleValue();
				double deltat = now() - before;
				deltaTime[index] += deltat;
			} else if (m instanceof Idle) {
				Idle e = (Idle) m;
				int index = e.getSystemElement().getOrdinal();
				eActivity[index] += now() - eActivation[index];
				eActivation[index] = -1;
			}
			break;
		default:
			assert false;
			break;
		}
	}

	@Override
	protected Statistics getResult(int nClient) {
		StatisticType [] types = res.getStatisticsTypes();
		SystemElement [] elements = res.getSystemElements();
		res.setNClient(nClient);
		double tEnd = SystemFactory.getTimeSimulation();
		//utimare i eActivity
		for(int i = 0; i < eActivation.length; i++){
			if(eActivation[i] != -1){
				double before = eActivation[i];
				eActivity[i]+= tEnd - before;
			}
		}
		for (int i = 0; i < elements.length; i++) {
			res.addStatistic(types[0], elements[i], eActivity[i] / tEnd);// utilizzazione //TODO
			res.addStatistic(types[1], elements[i],	pc[i] / tEnd);// troughtput
			res.addStatistic(types[2], elements[i], deltaTime[i] / pc[i]);// tempo di risposta
			res.addStatistic(types[3], elements[i], pc[i]);// clienti processati del sistema i
			res.addStatistic(types[4], elements[i], eActivity[i]);// delta t del sistema i
		}
		return res;
	}
}
